package com.client;


import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.control.LargeMapControl3D;
import com.google.gwt.maps.client.event.MarkerClickHandler;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.Size;
import com.google.gwt.maps.client.overlay.Icon;
import com.google.gwt.maps.utility.client.DefaultPackage;
import com.google.gwt.maps.utility.client.GoogleMapsUtility;
import com.google.gwt.maps.utility.client.labeledmarker.LabeledMarkerOptions;
import com.google.gwt.maps.utility.client.markerclusterer.MarkerClusterer;
import com.google.gwt.user.client.ui.Composite;

public class MapPanel extends Composite {
	
	private MapWidget map;
	private MyMarker marker;
	private MyMarker[] markers;
	private MyLabeledMarker[] labeledMarkers;
	MarkerClusterer clusterer;

	public MapPanel(int width,int height,double[] lat, double[] lng, long[] ids, String[] names, String[] markersLabels, final MarkerCallBack markerCallBack) {	
		map = new MapWidget();
		map.setSize(width+"px", height+"px");
		map.setScrollWheelZoomEnabled(true);
	    // Add some controls for the zoom level
		map.addControl(new LargeMapControl3D());
	    
	    
	    if(lat.length>1 && markersLabels != null){
	    	setMultiLabeledMarker(lat, lng, ids, names, markersLabels, markerCallBack, false);
	    	initWidget(map);
	    }
	    else if(lat.length>1 && markersLabels == null){
	    	setMultiMarker(lat, lng, ids, names, markerCallBack, false);
	    	initWidget(map);
	    }
	    else if(names!=null&&names.length>0)
	    	setSingleMarker(lat[0], lng[0], ids[0], names[0], markerCallBack, true);
	    else
	    	setSingleMarker(lat[0], lng[0], true);
	}

	public void setSingleMarker(double lat, double lng,boolean initMap){
		map.clearOverlays();
		LatLng location= LatLng.newInstance(lat, lng);
		marker= new MyMarker(location);
		map.addOverlay(marker);
		map.setCenter(location,7);
		if(initMap)
			initWidget(map);
	}

	public void setSingleMarker(double lat, double lng, long id, String name, final MarkerCallBack markerCallBack,boolean initMap){
		map.clearOverlays();
		LatLng location= LatLng.newInstance(lat, lng);
		marker= new MyMarker(location,id,name);
		marker.setId(id);
		marker.setName(name);
		marker.addMarkerClickHandler(new MarkerClickHandler() {
			@Override
			public void onClick(MarkerClickEvent event) {
				MyMarker m=(MyMarker) event.getSender();
				map.getInfoWindow().open(m.getLatLng(), new InfoWindowContent(m.getName()));
				markerCallBack.markerClicked(m.getId());
			}
		});
		map.addOverlay(marker);
		map.setCenter(location,7);
		if(initMap)
			initWidget(map);
	}

	public void setMultiLabeledMarker(final double[] lat, final double[] lng, final long[] ids, final String[] names, final String[] markersLabels, final MarkerCallBack markerCallBack,final boolean initMap){
		
		// Load Marker Clusterer Package and Labeled Marker
		if (!GoogleMapsUtility.isLoaded(DefaultPackage.MARKER_CLUSTERER, DefaultPackage.LABELED_MARKER)) {
		      GoogleMapsUtility.loadUtilityApi(new Runnable() {
		        public void run() {
		        	labeledMarkers= new MyLabeledMarker[lat.length];
		    		LatLng[] locations= new LatLng[lat.length];
		    		MyLabeledMarker tmp;
		    		Icon icon;
		    		for(int i=0;i<lat.length;i++){
		    			locations[i]= LatLng.newInstance(lat[i], lng[i]);
		    			icon = Icon.newInstance("http://gmaps-samples.googlecode.com/svn/trunk/markers/circular/yellowcirclemarker.png");
		    			tmp= createMarker(locations[i], icon, ids[i], names[i], markersLabels[i]);
		    			tmp.addMarkerClickHandler(new MarkerClickHandler() {
		    				@Override
		    				public void onClick(MarkerClickEvent event) {
		    					MyLabeledMarker m=(MyLabeledMarker) event.getSender();
		    					map.getInfoWindow().open(m.getLatLng(), new InfoWindowContent(m.getName()));
		    					markerCallBack.markerClicked(m.getId());
		    				}
		    			});
		    			labeledMarkers[i]=tmp;
		    		}
		        	map.setCenter(locations[locations.length-1],5);
		    		clusterer= MarkerClusterer.newInstance(map, labeledMarkers);
		        }
		      }, DefaultPackage.MARKER_CLUSTERER, DefaultPackage.LABELED_MARKER);
		}else{
			labeledMarkers= new MyLabeledMarker[lat.length];
    		LatLng[] locations= new LatLng[lat.length];
    		MyLabeledMarker tmp;
    		Icon icon;
    		for(int i=0;i<lat.length;i++){
    			locations[i]= LatLng.newInstance(lat[i], lng[i]);
    			icon = Icon.newInstance("http://gmaps-samples.googlecode.com/svn/trunk/markers/circular/yellowcirclemarker.png");
    			tmp= createMarker(locations[i], icon, ids[i], names[i], markersLabels[i]);
    			tmp.addMarkerClickHandler(new MarkerClickHandler() {
    				@Override
    				public void onClick(MarkerClickEvent event) {
    					MyLabeledMarker m=(MyLabeledMarker) event.getSender();
    					map.getInfoWindow().open(m.getLatLng(), new InfoWindowContent(m.getName()));
    					markerCallBack.markerClicked(m.getId());
    				}
    			});
    			labeledMarkers[i]=tmp;
    		}
			map.setCenter(locations[locations.length-1],5);
    		clusterer.clearMarkers();
    		clusterer.addMarkers(labeledMarkers);
    		if(initMap)
    			initWidget(map);
		}
	}
	
	public void setMultiMarker(final double[] lat, final double[] lng, final long[] ids, final String[] names, final MarkerCallBack markerCallBack,final boolean initMap){
		
		// Load Marker Clusterer Package and Labeled Marker
		if (!GoogleMapsUtility.isLoaded(DefaultPackage.MARKER_CLUSTERER, DefaultPackage.LABELED_MARKER)) {
		      GoogleMapsUtility.loadUtilityApi(new Runnable() {
		        public void run() {
		        	markers= new MyMarker[lat.length];
		    		LatLng[] locations= new LatLng[lat.length];
		    		MyMarker tmp;
		    		for(int i=0;i<lat.length;i++){
		    			locations[i]= LatLng.newInstance(lat[i], lng[i]);
		    			tmp= new MyMarker(locations[i], ids[i], names[i]);
		    			tmp.addMarkerClickHandler(new MarkerClickHandler() {
		    				@Override
		    				public void onClick(MarkerClickEvent event) {
		    					MyMarker m=(MyMarker) event.getSender();
		    					map.getInfoWindow().open(m.getLatLng(), new InfoWindowContent(m.getName()));
		    					markerCallBack.markerClicked(m.getId());
		    				}
		    			});
		    			markers[i]=tmp;
		    		}
		        	map.setCenter(locations[locations.length-1],5);
		    		clusterer= MarkerClusterer.newInstance(map, markers);
		        }
		      }, DefaultPackage.MARKER_CLUSTERER, DefaultPackage.LABELED_MARKER);
		}else{
			markers= new MyMarker[lat.length];
    		LatLng[] locations= new LatLng[lat.length];
    		MyMarker tmp;
    		for(int i=0;i<lat.length;i++){
    			locations[i]= LatLng.newInstance(lat[i], lng[i]);
    			tmp= new MyMarker(locations[i], ids[i], names[i]);
    			tmp.addMarkerClickHandler(new MarkerClickHandler() {
    				@Override
    				public void onClick(MarkerClickEvent event) {
    					MyMarker m=(MyMarker) event.getSender();
    					map.getInfoWindow().open(m.getLatLng(), new InfoWindowContent(m.getName()));
    					markerCallBack.markerClicked(m.getId());
    				}
    			});
    			markers[i]=tmp;
    		}
			map.setCenter(locations[locations.length-1],5);
    		clusterer.clearMarkers();
    		clusterer.addMarkers(markers);
    		if(initMap)
    			initWidget(map);
		}
	}
	
	public void addMarkers(double[] lat, double[] lng, long[] ids, String[] names, final MarkerCallBack markerCallBack){
		final MyMarker[] newMarkers= new MyMarker[lat.length+markers.length];
		final LatLng[] locations= new LatLng[lat.length];
		MyMarker tmp;
		for(int i=0;i<lat.length;i++){
			locations[i]= LatLng.newInstance(lat[i], lng[i]);
			tmp= new MyMarker(locations[i], ids[i], names[i]);
			tmp.addMarkerClickHandler(new MarkerClickHandler() {
				@Override
				public void onClick(MarkerClickEvent event) {
					MyMarker m=(MyMarker) event.getSender();
					map.getInfoWindow().open(m.getLatLng(), new InfoWindowContent(m.getName()));
					markerCallBack.markerClicked(m.getId());
				}
			});
			newMarkers[i]=tmp;
		}

		// Load Marker Clusterer Package
		if (!GoogleMapsUtility.isLoaded(DefaultPackage.MARKER_CLUSTERER)) {
		      GoogleMapsUtility.loadUtilityApi(new Runnable() {
		        public void run() {
		        	map.setCenter(locations[locations.length-1],5);
		        }
		      }, DefaultPackage.MARKER_CLUSTERER);
		}else{
			map.setCenter(locations[locations.length-1],5);
    		clusterer.addMarkers(newMarkers);
		}
		
		if(markers!=null){
			for(int i=0;i<markers.length;i++){
				newMarkers[lat.length+i]=markers[i];
			}
			markers=newMarkers;
		}
			
	}
	
	public void addlabeledMarkers(double[] lat, double[] lng, long[] ids, String[] names, String[] markersLabels, final MarkerCallBack markerCallBack){
		final MyLabeledMarker[] newMarkers= new MyLabeledMarker[lat.length+labeledMarkers.length];
		final LatLng[] locations= new LatLng[lat.length];
		MyLabeledMarker tmp;
		Icon  icon;
		for(int i=0;i<lat.length;i++){
			locations[i]= LatLng.newInstance(lat[i], lng[i]);
			icon = Icon.newInstance("http://gmaps-samples.googlecode.com/svn/trunk/markers/circular/yellowcirclemarker.png");
			tmp= createMarker(locations[i], icon, ids[i], names[i], markersLabels[i]);
			tmp.addMarkerClickHandler(new MarkerClickHandler() {
				@Override
				public void onClick(MarkerClickEvent event) {
					MyLabeledMarker m=(MyLabeledMarker) event.getSender();
					map.getInfoWindow().open(m.getLatLng(), new InfoWindowContent(m.getName()));
					markerCallBack.markerClicked(m.getId());
				}
			});
			newMarkers[i]=tmp;
		}

		// Load Marker Clusterer Package
		if (!GoogleMapsUtility.isLoaded(DefaultPackage.MARKER_CLUSTERER)) {
		      GoogleMapsUtility.loadUtilityApi(new Runnable() {
		        public void run() {
		        	map.setCenter(locations[locations.length-1],5);
		        }
		      }, DefaultPackage.MARKER_CLUSTERER);
		}else{
			map.setCenter(locations[locations.length-1],5);
    		clusterer.addMarkers(newMarkers);
		}
		
		if(labeledMarkers!=null){
			for(int i=0;i<labeledMarkers.length;i++){
				newMarkers[lat.length+i]=labeledMarkers[i];
			}
			labeledMarkers=newMarkers;
		}
			
	}
	
	private MyLabeledMarker createMarker(LatLng point, Icon icon, long id, String name, String label) {
		
		    LabeledMarkerOptions opts = LabeledMarkerOptions.newInstance();
		    opts.setIcon(icon);
		    opts.setClickable(true);
		    if(label.length()==1)
		    	opts.setLabelOffset(Size.newInstance(11, 6));
		    else if(label.length()==2)
		    	opts.setLabelOffset(Size.newInstance(8, 6));
		    else if(label.length()==3)
		    	opts.setLabelOffset(Size.newInstance(5, 6));
		    else
		    	opts.setLabelOffset(Size.newInstance(2, 0));
		    
		    opts.setLabelText(label);
		    opts.setLabelClass("hm-marker-label");
		    final MyLabeledMarker marker = new MyLabeledMarker(point, id, name, opts);
		    
		    return marker;
	}
	
	// for some reason clusterer.removeMarker(Marker m); fails
	/*public void removeMarkers(long[] ids){
		MyMarker[] newMarkers= new MyMarker[markers.length-ids.length];
		int newMarkersCount=0;
		if(clusterer!=null && markers!=null){
			for(int j=0;j<markers.length;j++){
				for(int i=0;i<ids.length;i++){
					if(markers[j].getId()==ids[i]){
						clusterer.removeMarker(markers[j]);
					}else{
						newMarkers[newMarkersCount]=markers[j];
						newMarkersCount++;
					}
				}
			}
			markers=newMarkers;
		}else if(map!=null){
			map.clearOverlays();
			markers=null;
			marker=null;
		}
	}*/

}
